#light

module Dwarf_Managed_Common

open System
open System.IO
open System.Text
open System.Collections.Generic
open System.Runtime.InteropServices
open System.Globalization
open Microsoft.FSharp.Core
open Microsoft.FSharp.NativeInterop

type TyRef = Microsoft.FSharp.Core.nativeptr<double>


/// <summary>
/// Start the time count.
/// </summary>
[<DllImport(@"CliTools.dll")>]
extern void start()

/// <summary>
/// Stop the time count.
/// </summary>
/// <param name="time">
/// Value of the time.
/// </param>
[<DllImport(@"CliTools.dll")>]
extern void stop(TyRef time)

/// <summary>
/// Default size for buffer.
/// </summary>
let BUFFER_SIZE = 1024;

/// <summary>
/// Constructor that init strings.
/// </summary>
let mutable inputFile = ""
let mutable profileFile = ""
let mutable resultFile = ""

/// <summary>
/// Number of rows in sparse matrix
/// </summary>
let mutable rowNum = 0 
/// <summary>
/// Number of non-zero values in sparse matrix
/// </summary>
let mutable valNum = 0

/// <summary>
/// sparse matrix in Compressed Row Storage (CRS) format
/// </summary>
let mutable value = Array.zeroCreate<Double> 0
let mutable col_ind = Array.zeroCreate<Int32> 0
let mutable row_ptr = Array.zeroCreate<Int32> 0

/// <summary>
/// Vector
/// </summary>
let mutable vector = Array.zeroCreate<Double> 0
/// <summary>
/// Result vector
/// </summary>
let mutable result = Array.zeroCreate<Double> 0

/// <summary>
/// Problem results output.
/// </summary>
/// <param name="dlasolver">
/// Instance of Solver.
/// </param>
let Finish () =
    let mutable time = 0.0
    stop(&&time)

    Console.WriteLine()
    Console.WriteLine("Clock time (sec): {0} ", time.ToString("F8"))

    try    
        use outputResult = System.IO.File.CreateText resultFile
        use outputProfile = System.IO.File.CreateText profileFile
        
        outputProfile.WriteLine("#Dwarfname:{0}", Constants.DWARF_NAME)

        outputProfile.WriteLine("#Time: {0}", DateTime.Now.ToString())
        
        outputProfile.WriteLine("#Matrix Row Number: {0}", rowNum);
        outputProfile.WriteLine("#Result time (sec): {0}", time.ToString("F8"))
        outputResult.WriteLine("#Result domain:")
        
        for i = 0 to rowNum - 1 do
            if (i <> 0) && (i % 20) = 0 then
                outputResult.WriteLine()
                
            outputResult.Write("{0} ", result.[i].ToString("F8", CultureInfo.InvariantCulture))
            
        outputResult.WriteLine()
        outputProfile.WriteLine("#eof")
 
    with e -> Console.WriteLine(e.Message); reraise()
        
/// <summary>
/// Start the time count.
/// </summary>
let Start() =
    start()

/// <summary>
/// Get one line from stream.
/// </summary>
/// <param name="dlasolver">
/// Stream to get from.
/// </param>
let GetLine(sr : StreamReader) =
    let mutable s = sr.ReadLine()

    //Avoid comments lines.
    while s.StartsWith("#") || s.StartsWith("//") do
        s <- sr.ReadLine()
        
    s

/// <summary>
/// Parse input file into solver's structures.
/// </summary>
/// <param name="dlasolver">
/// Instance of Solver.
/// </param>
let parseConfigFile() =
    // Open the file to read from.
    try        
        use sr = File.OpenText inputFile

        //Get number of rows.
        rowNum <- Int32.Parse(GetLine(sr))

        //Get number of non-zero values.
        valNum <- Int32.Parse(GetLine(sr))

        //Init arrays.
        value <- Array.zeroCreate<double> valNum 
        col_ind <- Array.zeroCreate<int> valNum
        row_ptr <- Array.zeroCreate<int> (rowNum + 1)
        vector <- Array.zeroCreate<double> rowNum
        result <- Array.zeroCreate<double> rowNum

        let mutable lastCount = -1
        let mutable count = -1

        //get val array of CRS
        let mutable str = GetLine(sr)
        for i = 0 to valNum - 1 do
            lastCount <- count + 1
            count <- str.IndexOf(' ', lastCount)

            value.[i] <- Double.Parse(str.Substring(lastCount, count - lastCount), CultureInfo.InvariantCulture)

        //get col_ind array of CRS
        count <- -1
        str <- GetLine(sr)
        for i = 0 to valNum - 1 do
            lastCount <- count + 1
            count <- str.IndexOf(' ', lastCount)

            col_ind.[i] <- Int32.Parse(str.Substring(lastCount, count - lastCount), CultureInfo.InvariantCulture)

        //get row_ptr array of CRS
        count <- -1
        str <- GetLine(sr)
        for i = 0 to rowNum do
            lastCount <- count + 1
            count <- str.IndexOf(' ', lastCount)

            row_ptr.[i] <- Int32.Parse(str.Substring(lastCount, count - lastCount), CultureInfo.InvariantCulture)            

        //get vector
        count <- -1
        str <- GetLine(sr)        
        for i = 0 to rowNum - 1 do
            lastCount <- count + 1
            count <- str.IndexOf(' ', lastCount)
            
            vector.[i] <- Double.Parse(str.Substring(lastCount, count - lastCount), CultureInfo.InvariantCulture)                    
          
    with e -> Console.WriteLine(e.Message); reraise()    
       

/// <summary>
/// Write settings.
/// </summary>
/// <param name="dlasolver">
/// Instance of Solver.
/// </param>
let WriteSettings() =
    // Write general settings.
    Console.WriteLine("Kernel settings summary : ")
    Console.WriteLine("Dwarf name              : {0} ", Constants.DWARF_NAME)
    Console.WriteLine("Matrix Row Number       : {0} ", rowNum)
    Console.WriteLine("Inputfile               : {0} ", inputFile)
    Console.WriteLine("Profilefile             : {0} ", profileFile)
    Console.WriteLine("Resultfile              : {0} ", resultFile)
    Console.WriteLine()

/// <summary>
/// Init variables, parse cli params and input file.
/// </summary>
/// <param name="args">
/// Cli params.
/// </param>
/// <param name="dlasolver">
/// Instance of Solver.
/// </param>
let Init(args : String[]) =
    
    for i = 0 to args.Length - 1 do
        let str = args.[i]
        
        if str.StartsWith("/inputfile:") then
            inputFile <- str.Substring(11)
            
        if str.StartsWith("/resultfile:") then
            resultFile <- str.Substring(12)
        
        if str.StartsWith("/profilefile:") then
            profileFile <- str.Substring(13)
            
    //Parse input file.
    parseConfigFile()

    // write settings if it's needed
    WriteSettings()
